//!
/**
 ***********************************************************************************************************
 * <RBWin32Application Implementation>
 ***********************************************************************************************************
 * @file RBWin32Application.cpp
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Precompiled Header
 ***********************************************************************************************************/
#include "RBApplicationPCH.h"

/***********************************************************************************************************
 * Includes
 ***********************************************************************************************************/
#include "RBWin32Application.h"

#include <RBMain/RBInput.h>

#include <windows.h>
#include <RBGLRenderer/RBGLRenderer.h>

/***********************************************************************************************************
 * Defines
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Classes implementation
 ***********************************************************************************************************/

// Facility to manage windows messages
class WindowsManager
{
public:
    static LRESULT CALLBACK     WindowProcedure     (HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam);
};

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBWin32Application::MainLoop(void* hWnd, RBFastDelegate<bool(void)> OnIdle)
{
    MSG msg;
    for (;;)
    {
        try
        {
            do 
            {
                while (PeekMessage(&msg,(HWND)hWnd,0,0,PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage( &msg);
                }

            } while (OnIdle());
        }
        catch (...)
        {
        }
    }
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void* RBWin32Application::InitWindow(void* hInstance, uint32 width, uint32 height)
{
    static TCHAR szAppName[] = TEXT ("RBApplication");
    WNDCLASSEX   wndclassex = {0};
    wndclassex.cbSize        = sizeof(WNDCLASSEX);
    wndclassex.style         = CS_HREDRAW | CS_VREDRAW;
    wndclassex.lpfnWndProc   = (WNDPROC)WindowsManager::WindowProcedure;
    //wndclassex.lpfnWndProc   = DefWindowProc;
    wndclassex.cbClsExtra    = 0;
    wndclassex.cbWndExtra    = 0;
    wndclassex.hInstance     = (HINSTANCE)hInstance;
    wndclassex.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    wndclassex.hCursor       = LoadCursor (NULL, IDC_ARROW);
    wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
    wndclassex.lpszMenuName  = NULL;
    wndclassex.lpszClassName = szAppName;
    wndclassex.hIconSm       = wndclassex.hIcon;

    if (!::RegisterClassEx(&wndclassex))
    {
        return false;
    }

    HWND hWnd = ::CreateWindow
    (
        szAppName, 
        szAppName, 
        WS_POPUP, //WS_POPUP | WS_CAPTION,
        CW_USEDEFAULT, 
        CW_USEDEFAULT, 
        width, 
        height,
        0,
        0, 
        wndclassex.hInstance, 
        0
    );


    if (!hWnd)
    {
        return false;
    }

    int32 iWindowMode = SW_SHOW;
    iWindowMode |= SW_SHOWNORMAL;

    iWindowMode = SW_SHOWDEFAULT;

    ::ShowWindow((HWND)hWnd, iWindowMode);
    
    if (!::UpdateWindow(hWnd))
    {
        return false;
    }

    return hWnd;
}

void RBWin32Application::ReleaseWindow(void*)
{

}

/***********************************************************************************************************
* Handles windows messages
***********************************************************************************************************/
LRESULT CALLBACK WindowsManager::WindowProcedure(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam)
{
    switch (uiMessage)
    {
    case WM_KEYDOWN:
        {
            RBInput::GetSingleton()->SetValue((RBInput::KeyType)wParam, RBInput::KS_DOWN);
        }
        break;
    case WM_KEYUP:
        {
            RBInput::GetSingleton()->SetValue((RBInput::KeyType)wParam, RBInput::KS_UP);
        }
        break;

    case WM_SYSCOMMAND:
        {
            if (wParam == SC_KEYMENU && lParam == VK_RETURN)
            {
                // ALT + RETURN
            }

            if ((wParam == SC_KEYMENU && lParam == VK_F4) || (wParam == SC_CLOSE))
            {
                // ALT + F4
                //GetApplication()->Exit();
            }
        }
        break;
    
    case WM_LBUTTONDOWN:
        RBInput::GetSingleton()->SetValue(RBInput::IK_LBUTTON, RBInput::KS_DOWN);
        break;

    case WM_LBUTTONUP:
        RBInput::GetSingleton()->SetValue(RBInput::IK_LBUTTON, RBInput::KS_UP);
        break;

    case WM_MBUTTONDOWN:
        RBInput::GetSingleton()->SetValue(RBInput::IK_MBUTTON, RBInput::KS_DOWN);
        break;

    case WM_MBUTTONUP:
        RBInput::GetSingleton()->SetValue(RBInput::IK_MBUTTON, RBInput::KS_UP);
        break;

    case WM_RBUTTONDOWN:
        RBInput::GetSingleton()->SetValue(RBInput::IK_RBUTTON, RBInput::KS_DOWN);
        break;

    case WM_RBUTTONUP:
        RBInput::GetSingleton()->SetValue(RBInput::IK_RBUTTON, RBInput::KS_UP);
        break;

    case WM_MOUSEMOVE:
        {
            #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
            #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
            RBInput::GetSingleton()->SetMousePos(int2(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)));
//            RBSystem::SetCursorPos(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
            return TRUE;

        }
        break;

    case WM_ACTIVATE:
        {
            if ((wParam == WA_ACTIVE) || (wParam == WA_CLICKACTIVE))
            {
                //while (::ShowCursor(0) > 0) {}
                //QueueMessage(EMessage::WINDOW_ACTIVATE);
            }

            if (wParam == WA_INACTIVE)
            {
                ::ShowCursor(1);
            }
        }
        break;

    case WM_POWERBROADCAST:
        {
            if (wParam == PBT_APMQUERYSUSPEND)
            {
                return BROADCAST_QUERY_DENY;
            }
        }
        break;

    case WM_DESTROY:
        {
            //GetApplication()->Exit();
        }
        break;

    default:
        {
            return DefWindowProc(hWindow,uiMessage,wParam,lParam);
        }
    }

    return 1;
}
